﻿/*
 * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
 */

#include "BurnCtrlJLink.h"
#include <QDir>
#include "../platform/Securec/securec.h"
using namespace BurnCtrlJlinkWorkerClass;
namespace  {
    const unsigned int ERASE_BYTE_SIZE_32K = 32 * 1024;
    using namespace BurnCtrlJLinkClass;
}

BurnCtrlJLink::BurnCtrlJLink(ChipType type, QObject *parent)
    : BurnCtrl(type, parent),
      proThread(nullptr),
      proWorker(nullptr),
      burnFlashCount(0),
      isStop(false)
{
    StartProWorker();
}

BurnCtrlJLink::~BurnCtrlJLink()
{
    if (proWorker != nullptr) {
        delete proWorker;
        proWorker = nullptr;
    }
    if (proThread != nullptr) {
        proThread->quit();
        proThread->wait();
        delete proThread;
        proThread = nullptr;
    }
}

void BurnCtrlJLink::InitBurnCmdByArray(const QMap<int, BIN_INFO> &infoArray)
{
    QString saveDir = QCoreApplication::applicationDirPath() + "/tempFileJlink";
    MakeDir(saveDir);
    this->infoArray.clear();
    for (auto iter = infoArray.begin(); iter != infoArray.end(); iter++) {
        if ((chipType == ChipType::JLINKBS2X || chipType == ChipType::JLINK2982) &&
            iter.value().type == IMAGE_TYPE::IMAGE_TYPE_LOADER) {
            continue;
        }
        BIN_INFO info;
        QFileInfo fileInfo(iter->path);
        QString strFileName;
        if (iter->fileName.isEmpty()) {
            strFileName = fileInfo.fileName();
        } else {
            strFileName = iter->fileName;
        }
        QString saveFile = saveDir + "/" + strFileName;
        QFile newFile(saveFile);
        QString cleanPath = QDir::cleanPath(iter->path);
        if (cleanPath.isEmpty()) {
            continue;
        }
        QFile oldFile(cleanPath);
        if (!oldFile.open(QIODevice::ReadOnly)) {
            continue;
        }
        if (newFile.exists()) {
            newFile.remove();
        }
        if (!newFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
            oldFile.close();
            continue;
        }
        oldFile.seek(DataConvertor::Str2U32DecHex(iter->fileIndex));
        QByteArray fileText = oldFile.read(DataConvertor::Str2U32DecHex(iter->fileSize));
        int ret = newFile.write(fileText);
        oldFile.close();
        newFile.close();
        if (ret == -1) {
            continue;
        }
        info = *iter;
        info.path = saveFile;
        this->infoArray[iter.key()] = info;
    }
    JlinkBs21WriteDtcm(saveDir);
}

void BurnCtrlJLink::MakeDir(const QString &path) const
{
    QDir dir(path);
    if (!dir.exists()) {
        dir.mkdir(path);
    }
}
void BurnCtrlJLink::JlinkBs21WriteDtcm(const QString &saveDir) const
{
    if (chipType == ChipType::JLINKBS2X || chipType == ChipType::JLINK2982) {
        char eraseByte[ERASE_BYTE_SIZE_32K] = {0};
        errno_t retMemset = memset_s(eraseByte, ERASE_BYTE_SIZE_32K, 0xff, ERASE_BYTE_SIZE_32K);
        if (retMemset != 0) {
            return;
        }
        QFile file(saveDir + "/dtcm.bin");
        if (file.open(QIODevice::WriteOnly)) {
            file.write(eraseByte, ERASE_BYTE_SIZE_32K);
        }
    }
}

void BurnCtrlJLink::StartConnect()
{
    if (infoArray.size() <= 0) {
        emit SignalBurnFileFailed();
        RemoveTempDir();
        return;
    }
    proWorker->SetInfoArray(infoArray);
    isStop = false;
    emit SignalEraseFlash();
}

void BurnCtrlJLink::StartProWorker()
{
    if (proWorker == nullptr) {
        proWorker = new BurnCtrlJlinkWorker();
    }
    if (proWorker == nullptr) {
        return;
    }
    if (proThread == nullptr) {
        proThread = new MyThreadClass::MyThread();
    }
    if (proThread == nullptr) {
        delete proWorker;
        proWorker = nullptr;
        return;
    }
    proWorker->moveToThread(proThread);
    connect(proThread, &QThread::finished, proWorker, &QObject::deleteLater);
    connect(this, &BurnCtrlJLink::SignalEraseFlash, proWorker, &BurnCtrlJlinkWorker::SlotEraseFlash);
    connect(this, &BurnCtrlJLink::SignalBurnFlash, proWorker, &BurnCtrlJlinkWorker::SlotBurnFlash);
    connect(proWorker, &BurnCtrlJlinkWorker::SignalEraseFlashSuccess, this, &BurnCtrlJLink::SlotEraseFlashSuccess);
    connect(proWorker, &BurnCtrlJlinkWorker::SignalEraseFlashFaild, this, &BurnCtrlJLink::SlotEraseFlashFaild);
    connect(proWorker, &BurnCtrlJlinkWorker::SignalBurnFlashSuccess, this, &BurnCtrlJLink::SlotBurnFlashSuccess);
    connect(proWorker, &BurnCtrlJlinkWorker::SignalBurnFlashStr, this, &BurnCtrlJLink::SlotBurnFlashStr);
    connect(proWorker, &BurnCtrlJlinkWorker::SignalBurnFlashFaild, this, &BurnCtrlJLink::SlotBurnFlashFaild);
    connect(proWorker, &BurnCtrlJlinkWorker::SignalSetProgressValue, this, &BurnCtrlJLink::SignalSetProgressValue);
    proThread->start();
}

void BurnCtrlJLink::SlotEraseFlashSuccess(const QString &str)
{
    emit SignalInsertPlainText(str);
    proWorker->SetInfoArray(infoArray);
    emit SignalBurnFlash();
}

void BurnCtrlJLink::SlotEraseFlashFaild()
{
    QString str = tr("Erase flash faild.");
    emit SignalInsertPlainText(str);
    RemoveTempDir();
    if (isOneTimeBurn != 0) {
        Sleep(500); // 延迟500ms退出
        Global::CloseApp(this->result);
    }
}

void BurnCtrlJLink::SlotBurnFlashSuccess()
{
    emit SignalBurnFileFinish();
    if (isOneTimeBurn != 0) {
        Sleep(500); // 延迟500ms退出
        Global::CloseApp(this->result);
    }
}

void BurnCtrlJLink::SlotBurnFlashStr(const QString &str)
{
    emit SignalInsertPlainText(str);
}

void BurnCtrlJLink::SlotBurnFlashFaild()
{
    if ((!isStop) && burnFlashCount <= 5) { // 烧写重试5次
        ++burnFlashCount;
        proWorker->StopProBurnStart();
        StartConnect();
    } else {
        burnFlashCount = 0;
        emit SignalBurnFileFailed();
        RemoveTempDir();
        if (isOneTimeBurn != 0) {
            Sleep(500); // 延迟500ms退出
            Global::CloseApp(this->result);
        }
    }
}

void BurnCtrlJLink::SlotCloseJlink()
{
    proWorker->StopProBurnStart();
    isStop = true;
}

void BurnCtrlJLink::RemoveTempDir() const
{
    QString saveDir = QCoreApplication::applicationDirPath() + "/tempFileJlink";
    QDir dir(saveDir);
    if (dir.exists()) {
        dir.removeRecursively();
    }
}
